import React, { useCallback, useEffect } from 'react';
import DataTable from '../base/DataTable';
import DataEdit from '../base/DataEdit';
import IconFont from '../base/IconFont';
import { useReducer, useMemo, useRef } from 'react';
import {
  isManager,
  removeKeys,
  batchSubmit,
  getFolwRunInfo,
  abort,
  activation,
} from '@/services/workflow';
import PageHeader from './PageHeader';
import { useModel } from 'umi';
import {
  Menu,
  Button,
  message,
  Space,
  Modal,
  Dropdown,
  Steps,
  Badge,
  List,
  Divider,
  Progress,
} from 'antd';
import ProForm, { ProFormTextArea } from '@ant-design/pro-form';
import type { ProFormInstance } from '@ant-design/pro-form';
import _ from 'lodash';
import { DownOutlined, ExclamationCircleOutlined } from '@ant-design/icons';
// 属性类型
type PropField = {
  /** 任务列表的后台dao名称*/
  taskDaoName: string;
  /** 任务列表的表格column列表*/
  taskColumns: API.Column[];
  /** 初始的排序*/
  initSorter?: API.OrderItem;
  /** 新增修改任务使用的control列表 */
  taskControls?: API.Control[];
  /** 编辑任务时使用的额外的值 */
  editExtraVals?: Record<string, any>;
  /** 流程的标题 */
  title?: string;
  /** 流程进度窗口显示标题，标题由指定字段名称的值拼接而成 */
  titleColNames: string[];
  /** 额外的按钮，比如新增、导入*/
  extraButtons?: JSX.Element;
  /** 主键列的名称，用于生成表格react.Key，以及保存数据，必须配置正确 */
  keyColName?: string;
  /** 是否显示新增按钮（默认的编辑功能） */
  canAdd?: boolean;
  /** 是否显示修改按钮（默认的编辑功能） */
  canUpdate?: boolean;
  /** 是否显示删除按钮 */
  canDelete?: boolean;
  /** 当前选择任务的引用*/
  selTaskDatas?: React.MutableRefObject<Record<string, any>[] | undefined>;
};
type StateField = {
  taskColumns?: API.Column[];
  isMg?: boolean;
  loading?: boolean;
  taskKeys?: number[];
  runStep?: JSX.Element;
  taskRows?: Record<string, any>[];
  taskDaoName?: string;
  range?: string;
  showType?: 'proposer' | 'approver';
  editType?: 'add' | 'update' | 'copyAdd';
  showEdit?: boolean;
};
const Workflow: React.FC<PropField> = (props) => {
  const { permTypes, curPermID, loadFlowDoing } = useModel('sysInfo', (ret) => ({
    permTypes: ret.getCurPermTypes(),
    curPermID: ret.curPermID,
    loadFlowDoing: ret.loadFlowDoing,
  }));
  const { user } = useModel('@@initialState', (ret) => ({
    user: ret.initialState?.user,
  }));
  const [state, dispatch] = useReducer(
    (prevState: StateField, newState: StateField) => {
      return { ...prevState, ...newState };
    },
    {
      taskColumns: props.taskColumns || [],
      isMg: false,
      loading: false,
      taskKeys: [],
      runStep: undefined,
      taskRows: [],
      taskDaoName: props.taskDaoName || '',
      range: permTypes && permTypes.includes('F') ? 'doing' : 'firstdoing',
      showType: permTypes && permTypes.includes('F') ? 'approver' : 'proposer',
      editType: 'add',
      showEdit: false,
    },
  );
  const tableRef = useRef<API.TableAction>();
  const descFormRef = useRef<ProFormInstance<any>>();
  useEffect(() => {
    isManager(curPermID)
      .then(function (data) {
        dispatch({ isMg: data });
      })
      .catch(function (ex) {
        console.error('判断流程管理员出错', ex);
      });
  }, [curPermID]);
  const getTitle = useCallback(
    (row: Record<string, any>) => {
      const titles: JSX.Element[] = [];
      props.titleColNames.forEach((t, i) => {
        titles.push(<span key={i as React.Key}>{row[t]}</span>);
      });
      return <Space key={row[props.keyColName!]}>{titles}</Space>;
    },
    [props.titleColNames, props.keyColName],
  );
  const loadRunStep = useCallback(
    (runID: number) => {
      getFolwRunInfo(state.taskDaoName!, runID)
        .then(function (flowRunInfo) {
          const steps = flowRunInfo.stepList.map((s) => {
            let desc = '未开始';
            if (flowRunInfo.state === '2' && flowRunInfo.currStep === s.id) {
              desc = '已中止';
            } else if (s.state === '1') {
              desc = '办理中...';
            } else if (s.state === '2') {
              desc = '已办理';
            }
            const content: JSX.Element[] = [];
            s.executors.map((e) => {
              let color = '';
              if (e.desc === '待办...' || e.desc === '未办') {
                color = 'gray';
              } else if (e.desc.substring(0, 2) === '中止' || e.desc === '管理员强制提交') {
                color = '#FA541C';
              } else {
                color = '#0D993A';
              }
              const c = (
                <div key={e.id}>
                  <span>{`${e.name}(${e.department}):`}</span> <br />
                  <span style={{ color: color }}>{e.desc}</span>
                </div>
              );
              content.push(c);
            });
            const descTag = <div style={{ maxHeight: '200px', overflow: 'auto' }}>{content}</div>;
            return (
              <Steps.Step key={s.id} title={s.name + `【` + desc + `】`} description={descTag} />
            );
          });
          let status: 'wait' | 'process' | 'finish' | 'error' = 'process';
          if (flowRunInfo.state === '1') {
            status = 'finish';
          } else if (flowRunInfo.state === '2') {
            status = 'error';
          } else {
            const step = flowRunInfo.stepList[flowRunInfo.currStep - 1];
            if (step.appointer && step.appointer.length > 0 && step.executors.length == 0) {
              status = 'wait';
            }
          }
          const current = flowRunInfo.currStep - 1;
          const row = state.taskRows!.find((r) => r[props.keyColName!] === runID);
          const runStep = (
            <Modal
              title={row ? getTitle(row) : ''}
              width={600}
              visible={true}
              onCancel={() => dispatch({ runStep: undefined })}
              footer={false}
            >
              <Steps direction="vertical" current={current} status={status}>
                {steps}
              </Steps>
            </Modal>
          );
          dispatch({ runStep: runStep });
        })
        .catch(function (ex) {
          console.error('判断流程管理员出错', ex);
          return;
        });
    },
    [getTitle, state.taskDaoName, state.taskRows, props.keyColName],
  );
  const toolBar = useMemo(() => {
    if (_.isEmpty(permTypes)) {
      return;
    }
    const rangeChange = (key: string) => {
      dispatch({ range: key, taskKeys: [] });
    };
    const showTypeChange = (key: 'proposer' | 'approver') => {
      const range = key === 'proposer' ? 'firstdoing' : 'doing';
      dispatch({ showType: key, range, taskKeys: [] });
    };
    const deleteHandler = () => {
      if (_.isEmpty(state.taskKeys)) {
        message.info('请选择要删除的申请');
        return;
      }
      Modal.confirm({
        title: '提示',
        icon: <ExclamationCircleOutlined />,
        content: `您确定要删除选中${state.taskKeys!.length}笔申请吗？`,
        onOk: () => {
          dispatch({ loading: true });
          removeKeys(props.taskDaoName, state.taskKeys!)
            .then(function (data) {
              if (data === 'OK') {
                if (!_.isEmpty(tableRef.current)) {
                  tableRef.current?.reload();
                }
                loadFlowDoing();
              }
            })
            .catch(function (ex) {
              console.error('删除流程出错', ex);
            })
            .finally(function () {
              dispatch({ loading: false });
            });
        },
        okText: '确认',
        cancelText: '取消',
      });
    };
    const batchSubmitHandler = () => {
      if (_.isEmpty(state.taskKeys)) {
        message.info('请选择要提交的申请');
        return;
      }
      const isMg = state.range !== 'doing' && state.isMg;
      Modal.confirm({
        title: (
          <div key="1">
            你确认要{isMg ? '强制' : ''}提交选中的
            <Badge
              count={state.taskKeys!.length}
              overflowCount={100}
              style={{ backgroundColor: '#87d068' }}
            />
            笔申请吗？{isMg ? '强制提交将跳过没有审批的节点直接生效！' : ''}
          </div>
        ),
        icon: <ExclamationCircleOutlined />,
        width: 800,
        content: (
          <div style={{ maxHeight: 600, overflow: 'auto' }}>
            <List
              size="small"
              dataSource={state.taskRows!.map((row) => (
                <>
                  {getTitle(row)}
                  {
                    <a
                      style={{ marginLeft: 10 }}
                      onClick={() => {
                        loadRunStep(row[props.keyColName!]);
                      }}
                    >
                      进度
                    </a>
                  }
                </>
              ))}
              renderItem={(item) => <List.Item>{item}</List.Item>}
            />
            {isMg ? (
              <>
                <Divider />
                <ProForm formRef={descFormRef} layout="vertical" submitter={false}>
                  <ProFormTextArea
                    name="desc"
                    label="请填写强制提交的原因(200字以内)"
                    fieldProps={{ maxLength: 200 }}
                  />
                </ProForm>
              </>
            ) : null}
          </div>
        ),
        onOk: () => {
          let desc = '';
          if (isMg) {
            desc = descFormRef.current?.getFieldValue('desc');
            if (_.isEmpty(desc)) {
              message.error('您必须填写强制提交的原因');
              return;
            }
          }
          batchSubmit(props.taskDaoName, state.taskKeys!, user!.userID!, desc, '')
            .then(function () {
              message.success('流程提交成功');
              if (!_.isEmpty(tableRef.current)) {
                tableRef.current?.reload();
              }
              loadFlowDoing();
            })
            .catch(function (ex) {
              console.error('流程提交出错', ex);
            });
        },
        okText: '确认',
        cancelText: '取消',
      });
    };
    const abortHandler = () => {
      if (_.isEmpty(state.taskKeys)) {
        message.info('请选择要中止的申请');
        return;
      }
      Modal.confirm({
        title: '提示',
        content: `你确认要中止选中的${state.taskKeys!.length}笔申请吗？`,
        okText: '中止',
        cancelText: '取消',
        onOk: () => {
          abort(state.taskKeys!, props.taskDaoName)
            .then(function () {
              message.success('流程中止成功');
              if (!_.isEmpty(tableRef.current)) {
                tableRef.current?.reload();
              }
              loadFlowDoing();
            })
            .catch(function (ex) {
              console.error('流程中止出错', ex);
            });
        },
      });
    };
    const actHandler = () => {
      if (_.isEmpty(state.taskKeys)) {
        message.info('请选择要中止的申请');
        return;
      }
      Modal.confirm({
        title: '提示',
        content: `你确认要激活选中的${state.taskKeys!.length}笔申请吗？`,
        okText: '激活',
        cancelText: '取消',
        onOk: () => {
          activation(state.taskKeys!)
            .then(function () {
              message.success('流程激活成功');
              if (!_.isEmpty(tableRef.current)) {
                tableRef.current?.reload();
              }
              loadFlowDoing();
            })
            .catch(function (ex) {
              console.error('流程激活出错', ex);
            });
        },
      });
    };
    const openEdit = (type: 'add' | 'update' | 'copyAdd') => {
      if (type !== 'add') {
        if (_.isEmpty(state.taskKeys)) {
          message.warn('请选择要修改的数据行');
          return;
        }
      }
      dispatch({ editType: type, showEdit: true });
    };
    const menu1 = (
      <Menu onClick={(e) => showTypeChange(e.key as 'proposer' | 'approver')}>
        <Menu.Item key="approver">我的审批</Menu.Item>
        <Menu.Item key="proposer">我的申请</Menu.Item>
      </Menu>
    );
    const isap = state.showType === 'proposer';
    const menu2 = (
      <Menu onClick={(e) => rangeChange(e.key)}>
        <Menu.Item key={isap ? 'firstdoing' : 'doing'}>待办理</Menu.Item>
        <Menu.Item key={isap ? 'firstdone' : 'done'}>已提交</Menu.Item>
        <Menu.Item key={isap ? 'firstfinish' : 'finish'}>已完结</Menu.Item>
        <Menu.Item key={isap ? 'firstaborted' : 'aborted'}>已中止</Menu.Item>
        {state.isMg ? <Menu.Item key="manager">管理</Menu.Item> : null}
      </Menu>
    );
    return (
      <Space style={{ marginTop: -10, marginBottom: 10 }}>
        <Dropdown overlay={menu1} trigger={['click']}>
          <Button type="ghost">
            {state.showType === 'approver' ? '我的审批' : '我的申请'}
            <DownOutlined />
          </Button>
        </Dropdown>
        <Dropdown overlay={menu2} trigger={['click']}>
          <Button type="ghost">
            {state.range === 'firstdoing' || state.range === 'doing'
              ? '待办理'
              : state.range === 'firstdone' || state.range === 'done'
              ? '已提交'
              : state.range === 'firstfinish' || state.range === 'finish'
              ? '已完结'
              : state.range === 'firstaborted' || state.range === 'aborted'
              ? '已中止'
              : '管理'}
            <DownOutlined />
          </Button>
        </Dropdown>
        {(state.range === 'firstdoing' || state.range === 'doing') && props.extraButtons
          ? props.extraButtons
          : null}
        {state.range === 'firstdoing' && props.canAdd ? (
          <Button key="add" onClick={() => openEdit('add')}>
            <IconFont type="icon-xinzeng" />
            新增
          </Button>
        ) : null}
        {state.range === 'firstdoing' && props.canUpdate ? (
          <Button key="update" onClick={() => openEdit('update')}>
            <IconFont type="icon-xiugai" />
            修改
          </Button>
        ) : null}
        {state.range === 'firstdoing' && props.canDelete ? (
          <Button onClick={deleteHandler} disabled={state.loading}>
            <IconFont type="icon-shanchu" />
            删除
          </Button>
        ) : null}
        <Button
          onClick={() => {
            if (_.isEmpty(state.taskKeys)) {
              message.info('请选择要查看的申请');
              return;
            }
            loadRunStep(state.taskKeys![state.taskKeys!.length - 1]);
          }}
        >
          <IconFont type="icon-chakanjindu" />
          查看进度
        </Button>
        {state.range === 'firstdoing' || state.range === 'doing' || state.range === 'manager' ? (
          <Button onClick={batchSubmitHandler} disabled={state.loading}>
            <IconFont type="icon-tijiao" />
            提交
          </Button>
        ) : null}
        {state.range === 'manager' || state.range === 'doing' ? (
          <Button onClick={abortHandler} disabled={state.loading}>
            <IconFont type="icon-zhongzhi" />
            中止
          </Button>
        ) : null}
        {state.range === 'manager' ? (
          <Button onClick={actHandler} disabled={state.loading}>
            <IconFont type="icon-jihuo" />
            激活
          </Button>
        ) : null}
      </Space>
    );
  }, [
    state.isMg,
    permTypes,
    props.taskDaoName,
    state.taskKeys,
    state.taskRows,
    user,
    getTitle,
    loadFlowDoing,
    loadRunStep,
    state.loading,
    state.range,
    props.extraButtons,
    state.showType,
    props.canDelete,
    props.canAdd,
    props.canUpdate,
    props.keyColName,
  ]);
  const dataTable = useMemo(() => {
    if (_.isEmpty(state.taskDaoName) || _.isEmpty(state.taskColumns) || _.isEmpty(state.range)) {
      return;
    }
    const renderStep = (progress: number, status: string) => {
      const percent = Math.round(progress);
      return (
        <Progress
          percent={percent}
          size="small"
          status={
            status === '' ? 'normal' : (status as 'success' | 'normal' | 'exception' | 'active')
          }
        />
      );
    };
    const stepCol: API.Column = {
      title: '当前进度',
      key: 'StepName',
      render: (row: Record<string, any>) => renderStep(row.progress, row.status),
      width: 140,
      dispaly: true,
    };
    return (
      <DataTable
        daoName={state.taskDaoName!}
        columns={[stepCol, ...state.taskColumns!]}
        keyColName={props.keyColName}
        initSorter={props.initSorter}
        pageSize={20}
        controls={props.taskControls}
        seeks={[
          {
            WhereItems: [
              {
                FieldName: '#flowType',
                Operator: '=',
                FieldValues: state.range!,
              },
            ],
            RelationSign: 'AND',
          },
        ]}
        actionRef={tableRef}
        title={props.title}
        multiSelect={true}
        onSelectChange={async (keys, rows) => {
          const rIds = keys as number[];
          dispatch({ taskKeys: rIds, taskRows: rows });
        }}
      />
    );
  }, [
    state.taskDaoName,
    state.taskColumns,
    state.range,
    props.initSorter,
    props.keyColName,
    props.taskControls,
    props.title,
  ]);
  useEffect(() => {
    if (!_.isEmpty(props.selTaskDatas)) {
      props.selTaskDatas!.current = state.taskRows;
    }
    return () => {
      if (!_.isEmpty(props.selTaskDatas)) {
        props.selTaskDatas!.current = undefined;
      }
    };
  }, [props.selTaskDatas, state.taskRows]);
  const getInitVals = () => {
    let vals: Record<string, any> = {};
    if (state.editType === 'update') {
      vals = state.taskRows![0];
    }
    return vals;
  };
  return (
    <PageHeader>
      {toolBar}
      {dataTable}
      {state.runStep}
      {state.showEdit ? (
        <DataEdit
          key="edit"
          daoName={state.taskDaoName}
          keyColName={props.keyColName}
          title={props.title}
          controls={props.taskControls!}
          extraVals={props.editExtraVals}
          visible={state.showEdit}
          onSumit={async () => {
            tableRef.current?.reload();
          }}
          onVisibleChange={(visible) => dispatch({ showEdit: visible })}
          initVals={getInitVals()}
          renderButtons={(p) => {
            return [
              <Button type="default" key="rest" onClick={() => dispatch({ showEdit: false })}>
                取消
              </Button>,
              <Button type="primary" key="submit" onClick={() => p.form?.submit?.()}>
                保存
              </Button>,
            ];
          }}
        />
      ) : undefined}
    </PageHeader>
  );
};
Workflow.defaultProps = {
  title: '',
  initSorter: undefined,
  taskControls: [],
  keyColName: 'frid',
};

export default Workflow;
